package com.atguigu.gmall.cart.exception;

import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.index.qual.SameLen;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.io.StringReader;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;

/**捕获异步任务的异常信息   统一异常处理器 需要注册到配置类中  类似于拦截器
 * 如果返回值是非Future：通过统一的异常处理器 实现  AsyncUncaughtExceptionHandler接口
 * @author Jia Fa
 * @create 2021-12-19 23:57
 */
@Component
@Slf4j
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {

    @Autowired
    private StringRedisTemplate redisTemplate;

    private static final String EXCEPTION_KEY = "cart:exception:userId";

    @Override
    public void handleUncaughtException(Throwable ex, Method method, Object... params) {
        // 注意 userId 不能从线程变量中获取 由于这是异步线程 与保存到Redis中的不是一个线程
        // 所以要求所有的异步方法均需要传递一个userId 这样在params中就能直接获取到userId
        log.error("异常任务执行失败,失败方法{},参数为{},异常原因{}", method.getName(), Arrays.asList(params),ex.getMessage());
        // 已EXCEPTION_KEY 为key,userId 为value 使用set集合存储
        String userId = params[0].toString();
        // 用相同的key值进行存储 set集合令userId不重复
        BoundSetOperations<String, String> setOps = this.redisTemplate.boundSetOps(EXCEPTION_KEY);
        setOps.add(userId);
    }
}
